home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
programr
/
tkern10.zip
/
SRC\FORMATTR.C
< prev
next >
Wrap
Text File
|
1994-03-01
|
14KB
|
711 lines
/*
* This file forms part of "TKERN" - "Troy's Kernel for Windows".
*
* Copyright (C) 1994 Troy Rollo <troy@cbme.unsw.EDU.AU>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* __formattr does formatted output. It is here to serve all the printf
* type functions. They call __formatter with the address of a function
* that __formatter will call when it has a character, and a void pointer
* which is passwd to that function as the first argument. The character
* is passed as the second argument.
*
* This function can be safely placed in the DLL without sacrificing
* portability. It basically means that this module can be under GNU
* Library License without compromising any other programs using the
* stubs (which are freely redistributable and usable for any purpose
* whatsoever).
*
* Note that this also makes it trivial to design new printf type
* functions without resorting to sprintf on a large string.
*/
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <float.h>
#include <math.h>
#define FLAG_SHOWSIGN 0x0001
#define FLAG_LEFT 0x0002
#define FLAG_ZEROES 0x0004
#define FLAG_BLANK 0x0008
#define FLAG_ALTERNATE 0x0010
#define FLAG_UPPER 0x0020
#define FLAG_EXPONENTIAL 0x0040
#define FLAG_MAYEXP 0x0080
#pragma warn -pls
static char buffer[1024];
#pragma argsused
static int
show_integer( int (*func)(void *a, char b),
void *func_arg,
char const *pch,
char cSign,
int nWidth,
int nPrec,
int nFlags)
{
char cFill = ((nFlags & FLAG_ZEROES) ? '0' : ' ');
int iLen;
int nChars = 0;
iLen = strlen(pch) + (cSign ? 1 : 0);
if (iLen > nWidth)
nWidth = iLen;
else if (nWidth > iLen &&
(!(nFlags & FLAG_LEFT) ||
(nFlags & FLAG_ZEROES)))
{
if (cFill == '0' && cSign)
{
(*func)(func_arg, cSign);
cSign = '\0';
iLen--;
nWidth--;
nChars++;
}
while (nWidth > iLen)
{
nWidth--;
nChars++;
(*func)(func_arg, cFill);
}
}
if (cSign)
{
(*func)(func_arg, cSign);
iLen--;
nWidth--;
nChars++;
}
while (iLen--)
{
nWidth--;
(*func)(func_arg, *pch++);
nChars++;
}
while (nWidth--)
{
(*func)(func_arg, ' ');
nChars++;
}
return nChars;
}
static int
show_long( int (*func)(void *a, char b),
void *func_arg,
long number,
int nWidth,
int nPrec,
int nFlags)
{
char *pch = buffer;
char cSign = '\0';
int nLen;
ltoa(number, buffer, 10);
if (*pch == '-')
{
cSign = '-';
pch++;
}
else if (nFlags & FLAG_SHOWSIGN)
{
cSign = '+';
}
else if (nFlags & FLAG_BLANK)
{
cSign = ' ';
}
return show_integer(func, func_arg, pch, cSign, nWidth, nPrec, nFlags);
}
static int
show_ulong( int (*func)(void *a, char b),
void *func_arg,
long number,
int nWidth,
int nPrec,
int nFlags)
{
ultoa(number, buffer, 10);
return show_integer(func, func_arg, buffer, '\0', nWidth, nPrec, nFlags);
}
static int
show_hex( int (*func)(void *a, char b),
void *func_arg,
long number,
int nWidth,
int nPrec,
int nFlags)
{
ultoa(number, buffer, 16);
if (nFlags & FLAG_UPPER)
strupr(buffer);
return show_integer(func, func_arg, buffer, '\0', nWidth, nPrec, nFlags);
}
static int
show_real( int (*func)(void *a, char b),
void *func_arg,
long double fValue,
int nWidth,
int nPrecision,
int nFlags,
int nDigits)
{
int aiDigits[LDBL_DIG + 1];
long double fMantissa;
int nExponent;
int nSign = 1;
int nVisible;
char achExponent[10];
int nWritten = 0;
int iLastDigit;
int *piStart;
char *pchStart;
int i;
if (fValue < 0)
{
nSign = -1;
fValue = -fValue;
}
if (fValue)
nExponent = floor(log10(fValue));
else
nExponent = 0;
fMantissa = fValue / pow(10, nExponent);
aiDigits[0] = 0;
for (i = 1; i <= nDigits; i++)
{
if (fMantissa < 0) /* Rounding error */
fMantissa = 0;
aiDigits[i] = floor(fMantissa);
fMantissa = (fMantissa - aiDigits[i]) * 10;
}
for (; i < nDigits; i++)
{
aiDigits[i] = 0;
}
if (nPrecision == -1)
nPrecision = 6;
if (nFlags & FLAG_MAYEXP &&
nExponent >= 0 &&
nExponent +
(nPrecision ? nPrecision + 2 : 1) +
((nSign == -1 || (nFlags & FLAG_SHOWSIGN)) ? 1 : 0) > nWidth)
nFlags |= FLAG_EXPONENTIAL;
if (nFlags & FLAG_EXPONENTIAL)
{
ltoa(nExponent, achExponent, 10);
nVisible = 1 + (nPrecision ? nPrecision + 2 : 1) + strlen(achExponent);
}
else
{
if (nExponent < 0)
{
nVisible = nPrecision ? nPrecision : 1;
}
else
{
nVisible = nExponent + (nPrecision ? nPrecision + 2 : 1);
}
}
if (nSign == -1 || nFlags & FLAG_SHOWSIGN)
nVisible++;
if (!(nFlags & FLAG_LEFT))
{
while (nVisible < nWidth--)
{
(*func)(func_arg, ' ');
nWritten++;
}
}
if ((nFlags & FLAG_EXPONENTIAL) || nExponent < nDigits)
{
if ((nFlags & FLAG_EXPONENTIAL) || (nExponent < 0))
{
iLastDigit = 1 + nPrecision;
}
else
{
iLastDigit = 1 + nExponent + nPrecision;
}
if (iLastDigit < nDigits &&
aiDigits[iLastDigit+1] >= 5)
{
while (aiDigits[iLastDigit] == 9)
aiDigits[iLastDigit--] = 0;
aiDigits[iLastDigit]++;
}
}
if (nSign == -1)
{
(*func)(func_arg, '-');
nWritten++;
}
else if (nFlags & FLAG_SHOWSIGN)
{
(*func)(func_arg, '+');
}
if (aiDigits[0])
{
nExponent++;
piStart = aiDigits;
}
else
{
piStart = aiDigits + 1;
}
if (nFlags & FLAG_EXPONENTIAL)
{
(*func)(func_arg, '0' + *piStart++);
nWritten++;
if (nPrecision)
{
if (nPrecision > nDigits - 1)
nPrecision = nDigits - 1;
(*func)(func_arg, '.');
nWritten++;
while(nPrecision--)
{
(*func)(func_arg, '0' + *piStart++);
nWritten++;
}
if (nFlags & FLAG_UPPER)
(*func)(func_arg, 'E');
else
(*func)(func_arg, 'e');
nWritten++;
for (pchStart = achExponent; *pchStart; pchStart++)
{
(*func)(func_arg, *pchStart);
nWritten++;
}
}
}
else
{
if (nExponent >= 0)
{
while (nExponent-- >= 0)
{
if (nDigits-- > 0)
(*func)(func_arg, '0' + *piStart++);
else
(*func)(func_arg, '0');
nWritten++;
}
if (nPrecision)
{
(*func)(func_arg, '.');
nWritten++;
}
}
else
{
(*func)(func_arg, '0');
if (nPrecision)
(*func)(func_arg, '.');
while (nExponent++ && nPrecision--)
{
(*func)(func_arg, '0');
nWritten++;
}
}
while (nPrecision-- > 0)
{
if (nDigits-- > 0)
(*func)(func_arg, '0 ' + *piStart++);
else
(*func)(func_arg, '0');
nWritten++;
}
}
if (nFlags & FLAG_LEFT)
{
while (nVisible < nWidth--)
{
(*func)(func_arg, ' ');
nWritten++;
}
}
return nWritten;
}
int far _export
__formatter( int (*func)(void *a, char b),
void *func_arg,
char const *format,
va_list arg)
{
int nChars = 0;
int nPrecision;
int nWidth;
int nLong;
long nIntValue;
int nFlags;
int nPad;
int nLen;
union
{
short nShort;
int nInt;
long nLong;
unsigned short nUShort;
unsigned int nUInt;
unsigned long nULong;
float fFloat;
double fDouble;
long double fLongDouble;
char cChar;
char *pchString;
void *pvPointer;
} Value;
while (*format)
{
if (*format == '%')
{
if (*++format == '%')
{
(*func)(func_arg, '%');
nChars++;
}
else
{
nPrecision = -1;
nWidth = 0;
nLong = 0;
nFlags = 0;
while (strchr("+-0# ", *format))
{
switch(*format++)
{
case '+':
nFlags |= FLAG_SHOWSIGN;
break;
case '-':
nFlags |= FLAG_LEFT;
break;
case '#':
nFlags |= FLAG_ALTERNATE;
break;
case '0':
nFlags |= FLAG_ZEROES;
break;
case ' ':
nFlags |= FLAG_BLANK;
break;
}
}
if (isdigit(*format))
{
nWidth = (int) strtol((char *) format, (char **) &format, 10);
}
else if (*format == '*')
{
nWidth = va_arg(arg, int);
format++;
}
if (*format == '.')
{
++format;
if (isdigit(*format))
{
nPrecision = (int) strtol((char *) format, (char **) &format, 10);
}
else if (*format == '*')
{
nPrecision = (int) va_arg(arg, int);
format++;
}
}
while (strchr("lhL", *format))
{
if (*format == 'l')
nLong++;
else if (*format == 'h')
nLong--;
else if (*format == 'L')
nLong = 2;
format++;
}
switch(*format)
{
case 'u':
case 'U':
if (nLong < 0)
{
Value.nUShort = va_arg( arg,
unsigned short);
nChars += show_ulong( func,
func_arg,
Value.nUShort,
nWidth,
nPrecision,
nFlags);
}
else if (nLong == 0)
{
Value.nUInt = va_arg( arg,
unsigned int);
nChars += show_ulong( func,
func_arg,
Value.nUInt,
nWidth,
nPrecision,
nFlags);
}
else
{
Value.nULong = va_arg( arg,
unsigned long);
nChars += show_ulong( func,
func_arg,
Value.nULong,
nWidth,
nPrecision,
nFlags);
}
break;
case 'd':
case 'D':
case 'i':
case 'I':
if (nLong < 0)
{
Value.nShort = va_arg( arg,
short);
nChars += show_long( func,
func_arg,
Value.nShort,
nWidth,
nPrecision,
nFlags);
}
else if (nLong == 0)
{
Value.nInt = va_arg( arg,
int);
nChars += show_long( func,
func_arg,
Value.nInt,
nWidth,
nPrecision,
nFlags);
}
else
{
Value.nLong = va_arg( arg,
long);
nChars += show_ulong( func,
func_arg,
Value.nLong,
nWidth,
nPrecision,
nFlags);
}
break;
case 'n':
*(va_arg(arg, int *)) = nChars;
break;
case 's':
Value.pchString = va_arg( arg,
char *);
/* We can't do this in strlen, because we
* can't guarantee if there is a trailing
* 0 if we have a precision value
*/
for (nLen = 0;
(nPrecision < 0 ||
nLen < nPrecision) && Value.pchString[nLen];
nLen++);
if (nPrecision < 0 || nLen < nPrecision)
nPrecision = nLen;
if (!nWidth || nPrecision > nWidth)
nWidth = nPrecision;
nPad = nWidth - nPrecision;
if (!(nFlags & FLAG_LEFT))
{
while (nPad--)
{
(*func)(func_arg, ' ');
nChars++;
}
}
while (nPrecision--)
{
(*func)(func_arg, *Value.pchString++);
nChars++;
}
if (nFlags & FLAG_LEFT)
{
while (nPad--)
{
(*func)(func_arg, ' ');
nChars++;
}
}
break;
case 'o':
case 'O':
break;
case 'x':
case 'X':
if (*format == 'X')
nFlags |= FLAG_UPPER;
if (nLong < 0)
{
Value.nUShort = va_arg( arg,
unsigned short);
nChars += show_hex( func,
func_arg,
Value.nUShort,
nWidth,
nPrecision,
nFlags);
}
else if (nLong == 0)
{
Value.nUInt = va_arg( arg,
unsigned int);
nChars += show_hex( func,
func_arg,
Value.nUInt,
nWidth,
nPrecision,
nFlags);
}
else
{
Value.nULong = va_arg( arg,
unsigned long);
nChars += show_hex( func,
func_arg,
Value.nULong,
nWidth,
nPrecision,
nFlags);
}
break;
case 'c':
case 'C':
Value.cChar = va_arg( arg,
char);
(*func)(func_arg, Value.cChar);
nChars++;
break;
case 'P':
case 'p':
Value.pvPointer = va_arg(arg,
void *);
break;
case 'E':
case 'e':
nFlags |= FLAG_EXPONENTIAL;
case 'g':
case 'G':
nFlags |= FLAG_MAYEXP;
case 'F':
case 'f':
if (nLong > 1)
{
Value.fLongDouble = va_arg( arg,
long double);
nChars += show_real( func,
func_arg,
Value.fLongDouble,
nWidth,
nPrecision,
nFlags,
LDBL_DIG);
}
else if (nLong > 0)
{
Value.fDouble = va_arg( arg,
double);
nChars += show_real( func,
func_arg,
Value.fDouble,
nWidth,
nPrecision,
nFlags,
DBL_DIG);
}
else
{
Value.fFloat = va_arg( arg,
double);
nChars += show_real( func,
func_arg,
Value.fFloat,
nWidth,
nPrecision,
nFlags,
FLT_DIG);
}
break;
}
}
}
else
{
(*func)(func_arg, *format);
nChars++;
}
format++;
}
return nChars;
}